package pers.qianyu.diytomcat.util;

import cn.hutool.core.thread.*;
import cn.hutool.core.util.*;
import cn.hutool.crypto.*;
import pers.qianyu.diytomcat.http.*;

import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author mizzle rain
 * @date 2021-01-12 22:00
 */
public class SessionManager {
    private static Map<String, StandardSession> sessionMap = new ConcurrentHashMap<>();
    private static int defaultTimeout = WebXmlUtil.getSessionTimeout();

    static {
        startSessionExpireCheckThread();
    }

    private static void startSessionExpireCheckThread() {
        new Thread(() -> {
            while (true) {
                checkExpireSession();
                ThreadUtil.sleep(1 * 1000);
            }
        }).start();
    }

    private static void checkExpireSession() {
        Set<String> ids = sessionMap.keySet();
        ArrayList<String> expireIds = new ArrayList<>();
        for (String id : ids) {
            StandardSession session = sessionMap.get(id);
            if (System.currentTimeMillis() - session.getLastAccessedTime() >
                    session.getMaxInactiveInterval() * 1000) {
                expireIds.add(id);
            }
        }
        for (String id : expireIds) {
            sessionMap.remove(id);
            System.out.println("清理session：" + id);
        }
    }

    public static String generateSessionId() {
        byte[] bytes = RandomUtil.randomBytes(16);
        String s = SecureUtil.md5(new String(bytes));
        return s.toUpperCase();
    }

    public static HttpSession getSession(String id, Request req, Response res) {
        if (Objects.isNull(id)) {
            return newSession(req, res);
        }
        StandardSession session = sessionMap.get(id);
        if (Objects.isNull(session)) {
            return newSession(req, res);
        }
        session.setLastAccessedTime(System.currentTimeMillis());
        createCookieBySession(session, req, res);
        return session;
    }

    private static HttpSession newSession(Request req, Response res) {
        ServletContext servletContext = req.getServletContext();
        String id = generateSessionId();
        StandardSession session = new StandardSession(id, servletContext);
        session.setMaxInactiveInterval(defaultTimeout);
        session.setLastAccessedTime(System.currentTimeMillis());
        sessionMap.put(id, session);
        createCookieBySession(session, req, res);
        return session;
    }

    private static void createCookieBySession(StandardSession session, Request req, Response res) {
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setMaxAge(session.getMaxInactiveInterval());
        cookie.setPath(req.getContext().getPath());
        res.addCookie(cookie);
    }
}
